package sg.edu.nus.comp.cs4218.impl;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.Scanner;

import sg.edu.nus.comp.cs4218.extended2.ISortTool;

public class SortTool extends ATool implements ISortTool {

	/**
	 * Constructor
	 * 
	 * @param args
	 *            - Arguments the tool is going to be executed with.
	 */
	public SortTool(String[] args) {
		super(args);
	}

	/**
	 * Sort a string alphabetically
	 * 
	 * @param input
	 *            - A string representation to be sorted
	 * @return A string representation of the sorted content
	 */
	@Override
	public String sortFile(String input) {
		StringBuilder sb = new StringBuilder();
		String[] strArray = input.split("\n");
		Arrays.sort(strArray);
		for (int i = 0; i < strArray.length; i++) {
			sb.append(strArray[i] + "\n");
		}
		return sb.toString().trim();
	}

	/**
	 * Check if the string is sorted alphabetically
	 * 
	 * @param input
	 *            - A string representation to be sorted
	 * @return A string representation of the checking status: In order or a
	 *         diagnostic containing the first line that is out of order
	 */
	@Override
	public String checkIfSorted(String input) {
		String[] strArray = input.split("\n");
		String preLine = "";
		String thisLine = "";
		thisLine = strArray[0];
		preLine = thisLine;
		for (int i = 1; i < strArray.length; i++) {
			thisLine = strArray[i];
			if (preLine.compareTo(thisLine) > 0) {
				setStatusCode(0);
				return thisLine;
			}
			preLine = thisLine;
		}
		return "In order.";
	}

	/**
	 * Brief information about supported options
	 * 
	 * @return A string representation of the help message
	 */
	@Override
	public String getHelp() {
		setStatusCode(0);
		return "-c : Check whether the given file is already sorted, if it is not all sorted, print a\n"
				+ " diagnostic containing the first line that is out of order\n"
				+ " -help : Brief information about supported options";
	}

	/**
	 * An execute method used by other classes
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing stdin -
	 *            The standard input from users
	 * @return A string representation of the resulting outcome or error message
	 *         returned from the related method
	 */
	@Override
	public String execute(File workingDir, String stdin) {
		String result = null;
		if (args != null && args.length!=0) {
			result = null;
			if (args.length == 1) {
				result = oneArg(workingDir, stdin);
			} else {
				result = moreThanOneArg(workingDir, stdin);
			}

		} else {
			setStatusCode(1);
			result = "No argument.";
		}
		return result;
	}

	/**
	 * A method to be executed when there is only 1 argument
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing stdin -
	 *            The standard input from users
	 * @return A string representation of the resulting outcome or error message
	 *         returned from the related method
	 */
	private String oneArg(File workingDir, String stdin) {
		String result = null;
		String firstArg = args[0];
		if (firstArg.equals("-help")) {
			result = getHelp();
		} else if (firstArg.equals("-")) {
			result = sortFile(stdin);
		} else if (isExisting(workingDir, firstArg)) {
			String content = readContentFromFile(workingDir, firstArg);
			result = sortFile(content);
		} else {
			setStatusCode(1);
			result = "Wrong command.";
		}
		return result;
	}

	/**
	 * A method to be executed when there is more than 1 argument
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing stdin -
	 *            The standard input from users
	 * @return A string representation of the resulting outcome or error message
	 *         returned from the related method
	 */
	private String moreThanOneArg(File workingDir, String stdin) {
		StringBuilder sb = new StringBuilder();
		if (args[0].equals("-c")) {
			if (args[1].equals("-")) {
				sb.append(checkIfSorted(stdin));
			} else {
				for (int i = 1; i < args.length; i++) {
					if (isExisting(workingDir, args[i])) {
						sb.append(sortOrCheckFile(workingDir, args[i], "check")
								+ "\n");
					} else {
						sb = new StringBuilder();
						setStatusCode(1);
						String filePathWithName = workingDir.toString() + "\\"
								+ args[i] + " was not found.";
						sb.append(filePathWithName);
						break;
					}
				}
			}
		} else {
			for (int i = 0; i < args.length; i++) {
				if (isExisting(workingDir, args[i])) {
					sb.append(sortOrCheckFile(workingDir, args[i], "sort")
							+ "\n");
				} else {
					sb = new StringBuilder();
					setStatusCode(1);
					String filePathWithName = workingDir.toString() + "\\"
							+ args[i] + " was not found.";
					sb.append(filePathWithName);
					break;
				}

			}
		}
		return sb.toString().trim();
	}

	/**
	 * A method to be called and execute the corresponding operation: check or
	 * sort
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing stdin -
	 *            The standard input from users
	 *         soc 
	 *            - soc must be "check" or "sort"
	 * @return A string representation of the resulting outcome or error message
	 *         returned from the related method
	 */
	private String sortOrCheckFile(File workingDir, String fileName, String soc) {
		String result = null;
			String content = readContentFromFile(workingDir, fileName);
			if (soc.equals("check")) {
				result = checkIfSorted(content);
			} else {
				result = sortFile(content);
			}
		return result;
	}

	/**
	 * A method to check if a file is existing in the working directory
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing fileName -
	 *            A string representation of the file name
	 * @return A boolean representation if the file is existing
	 */
	private boolean isExisting(File workingDir, String fileName) {
		File f = new File(workingDir, fileName);
		if (f.exists()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * A method to be called when reading the contents of a specified file
	 * 
	 * @param workingDir
	 *            - The working directory where the files are storing fileName -
	 *            A string representation of the file name
	 * @return A string representation of the contents of the file or error
	 *         message
	 */
	private static String readContentFromFile(File workingDir, String fileName) {
		String content = "";
		Scanner in = null;
		try {
			File f = new File(workingDir, fileName);
			in = new Scanner(f);
			while (in.hasNextLine()) {
				content = content + in.nextLine() + "\n";
			}

		} catch (FileNotFoundException e) {
			content = fileName + " not found.";
		} finally {
			in.close();
		}
		return content.trim();
	}

}
